/* File Name : EventDispatcher.java */
//Jose Heitor

package com.chenwenxuan.sync.event;
 
import java.util.Observable;  // * Template Dispatcher Class - must import & extend [Observable]
import java.util.concurrent.ConcurrentLinkedQueue;
 
// This class is typically instantiated by the 'EventDelegate' class, to dispatch notifications
// of a particular event to all registered parties (EventObserver objects).
class EventDispatcher extends Observable implements Runnable
{
  // Reference to the source object that generates events
  private final IEventSource src;
  private final int threadPriority;
  private final boolean queue;
  
  private boolean active = false;
  private Object params;
  private ConcurrentLinkedQueue<Object> eventQueue;
  
  // Optional constructor. Requires a reference to the source of the event
  public EventDispatcher(IEventSource source)
  {
    this(source, 0, false);
  }
  
  // Optional constructor. Requires a reference to the source of the event
  public EventDispatcher(IEventSource source, int threadPriority)
  {
    this(source, threadPriority, false);
  }
  
  // Default constructor. Requires a reference to the source of the event and the Threadind
  // model/priority and whether a queue is to be used by this object
  public EventDispatcher(IEventSource source, int threadPriority, boolean queue)
  {
    src = source;
    switch (threadPriority)
    {
      case 1:
        this.threadPriority = 100;
        break;
      case 2:
        this.threadPriority = 200;
        break;
      case 3:
        this.threadPriority = 300;
        break;
      case 4:
        this.threadPriority = 400;
        break;
      case 5:
        this.threadPriority = 500;
        break;
      default: this.threadPriority = 0;
    }
    this.queue = queue;
    if (queue)
    {
      eventQueue = new ConcurrentLinkedQueue<Object>();
    }
  }
  
  // Method called from 'EventDelegate' object to dispatch this event
  // to all registered observers (EventObserver objects)
  public void dispatchEvent(Object params)
  {
    setChanged();
    if (!active)
    {
      notifyObservers(params);
    }
    else
    {
      if (queue && (eventQueue.size() < Integer.MAX_VALUE))
      {
        if (params == null)
        {
          eventQueue.add(new Empty());
        }
        else
        {
          eventQueue.add(params);
        }
      }
      else
      {
        this.params = params;
      }
    }
  }
  
  // Observers can obtain a reference to the source of this event through this method call
  public IEventSource getSource()
  {
    return src;
  }
  
  // Implementation of the Runnable interface - so this can be run in a separate thread.
  public void run()
  {
    Object obj;
    active = true;
    while(active)
    {
      try
      {
        Thread.sleep(threadPriority);
      }
      catch(InterruptedException e)
      {
        e.printStackTrace();
        return;
      }
      if (hasChanged())
      {
        if (queue)
        {
          while (eventQueue.size() > 0)
          {
            setChanged();
            obj = eventQueue.poll();
            if (ClassUtils.getClassName(obj.getClass()).equals("Empty"))
            {
              notifyObservers(null);
            }
            else
            {
              notifyObservers(obj);
            }
          }
        }
        else
        {
          notifyObservers(params);
        }
      }
    }
  }
  
  // Shuts down this thread (when running in a separate thread)
  public void deActivate()
  {
    active = false;
  }
}
